<script setup lang="ts" name="ListenersDrawer">
import { mapState } from 'pinia'
import { useModelerStore } from '@/store/bpmnProcess/modelerStore'
import useMessageBox from '@/hooks/useMessageBox'
import { getDefaultEvent, getListenerEventTypeOptions, getListenerTypeOptions, getListenerTypeObject } from '../../../../utils/listeners'
import { getScriptTypeList } from '../../../../utils'
import FieldsAddEdit from './FieldsAddEdit.vue'

const { messageBox } = useMessageBox()

const listenerFormRef = ref(null)
const FieldsAddEditRef = ref(null)

const emit = defineEmits(['save'])

const visible = ref(false)

const fieldType = ref({
  string: '字符串',
  expression: '表达式'
})

const form: any = ref({
  event: '',
  id: '',
  type: '',
  class: '',
  expression: '',
  delegateExpression: '',
  script: {
    scriptFormat: '',
    scriptType: '',
    value: '',
    resource: ''
  },
  fields: []
})

const editIndex = ref(-1)

const mapStates = computed(() => {
  return mapState(useModelerStore, ['getActive'])
})

const listenerTypeOptions = ref([])
const listenerTypeObject = ref(null)
const listenerEventTypeOptions = ref([])
const scriptTypeList = ref([])
const type = ref('')

const showDrawer = (v) => {
  type.value = v.type
  if (v.row) {
    form.value.event = v.row.event
    if (type.value === 'TaskListener') {
      form.value.id = v.row.id
    }
    form.value.type = v.row.type
    if (v.row.type === 'class') {
      form.value.class = v.row.class
    } else if (v.row.type === 'expression') {
      form.value.expression = v.row.expression
    } else if (v.row.type === 'delegateExpression') {
      form.value.delegateExpression = v.row.delegateExpression
    } else {
      form.value.script.scriptType = v.row.script.scriptType
      form.value.script.scriptFormat = v.row.script.scriptFormat
      form.value.script.value = v.row.script.value
      form.value.script.resource = v.row.script.resource
    }
    if (v.row.fields) {
      v.row.fields.forEach((item: any) => {
        const res = {
          name: item.name
        }
        if (item.string) {
          res['string'] = item.string
          res['fieldType'] = 'string'
        } else {
          res['expression'] = item.expression
          res['fieldType'] = 'expression'
        }
        form.value.fields.push(res)
      })
    }
  } else {
    form.value.event = getDefaultEvent(mapStates.value.getActive(), type.value)
    form.value.type = 'expression'
  }
  visible.value = true
  listenerEventTypeOptions.value = getListenerEventTypeOptions(mapStates.value.getActive(), type.value)
  listenerTypeOptions.value = getListenerTypeOptions()
  listenerTypeObject.value = getListenerTypeObject()
  scriptTypeList.value = getScriptTypeList()
}
defineExpose({ showDrawer })

// 新增注入字段
const add = () => {
  editIndex.value = -1
  FieldsAddEditRef.value.showDialog()
}

// 编辑注入字段
const edit = (row, idx) => {
  editIndex.value = idx
  FieldsAddEditRef.value.showDialog(row)
}

// 删除注入字段
const deleteRow = (index) => {
  const msg = '确认<span>删除</span>该字段吗？'
  const msgTips = ''
  messageBox('danger', true, msg, msgTips, () => {
    form.value.fields.splice(index, 1)
  })
}

// 注入字段数据更新
const fieldListChange = (v) => {
  if (editIndex.value === -1) {
    form.value.fields.push(v)
  } else {
    form.value.fields.splice(editIndex.value, 1, v)
  }
}

// 关闭抽屉
const cancel = () => {
  listenerFormRef.value.resetFields()
  form.value = {
    event: '',
    id: '',
    type: '',
    class: '',
    expression: '',
    delegateExpression: '',
    script: {
      scriptFormat: '',
      scriptType: '',
      value: '',
      resource: ''
    },
    fields: []
  }
  listenerEventTypeOptions.value = []
  listenerTypeOptions.value = []
  listenerTypeObject.value = null
  visible.value = false
}

// 保存监听器数据
const save = async () => {
  await listenerFormRef.value.validate((validate) => {
    if (validate) {
      const result = {
        event: form.value.event,
        type: form.value.type
      }
      if (type.value === 'TaskListener') {
        result['id'] = form.value.id
      }
      if (form.value.type === 'class') {
        result['class'] = form.value.class
      } else if (form.value.type === 'expression') {
        result['expression'] = form.value.expression
      } else if (form.value.type === 'delegateExpression') {
        result['delegateExpression'] = form.value.delegateExpression
      } else if (form.value.type === 'script') {
        result['script'] = form.value.script
      }
      if (form.value.fields.length > 0) {
        result['fields'] = form.value.fields
      }
      emit('save', result)
      cancel()
    }
  })
}
</script>

<template>
  <el-drawer class="listener-drawer" v-model="visible" direction="rtl" destroy-on-close size="580px" :before-close="cancel">
    <template #header>
      <h2>{{ type === 'TaskListener' ? '任务' : '执行' }}监听器</h2>
    </template>
    <template #default>
      <el-form :model="form" label-width="auto" label-position="right" ref="listenerFormRef" @submit.prevent>
        <el-form-item label="事件类型" prop="event" :rules="{ required: true, trigger: ['blur', 'change'], message: '事件类型不能为空' }">
          <el-select v-model="form.event">
            <el-option v-for="item in listenerEventTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item v-if="type === 'TaskListener'" label="监听器ID" prop="id" :rules="{ required: true, trigger: ['blur', 'change'], message: '监听器ID不能为空' }">
          <el-input v-model="form.id" />
        </el-form-item>
        <el-form-item label="监听器类型" prop="type" :rules="{ required: true, trigger: ['blur', 'change'], message: '监听器类型不能为空' }">
          <el-select v-model="form.type">
            <el-option v-for="item in listenerTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </el-form-item>
        <template v-if="form.type !== ''">
          <template v-if="form.type !== 'script'">
            <el-form-item :label="listenerTypeObject[form.type]" :key="form.type" :prop="form.type" :rules="{ required: true, trigger: ['blur', 'change'], message: listenerTypeObject[form.type] + '不能为空' }">
              <el-input type="textarea" v-model="form[form.type]" />
            </el-form-item>
          </template>
          <template v-else>
            <el-form-item label="脚本格式" prop="script.scriptFormat" :rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }">
              <el-input v-model="form.script.scriptFormat" />
            </el-form-item>
            <el-form-item label="脚本类型" prop="script.scriptType" :rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }">
              <el-select v-model="form.script.scriptType">
                <el-option v-for="item in scriptTypeList" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </el-form-item>
            <el-form-item v-if="form.script.scriptType && form.script.scriptType === 'inline'" label="脚本内容" prop="script.value" :rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }">
              <el-input type="textarea" v-model="form.script.value" />
            </el-form-item>
            <el-form-item v-if="form.script.scriptType && form.script.scriptType === 'external'" label="资源地址" prop="script.resource" :rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }">
              <el-input type="textarea" v-model="form.script.resource" />
            </el-form-item>
          </template>
        </template>
      </el-form>
      <div class="field-content">
        <el-divider>
          <div class="divider-panel">
            <svg-icon icon="ri:code-s-slash-line"></svg-icon>
            <span>注入字段</span>
          </div>
        </el-divider>
        <el-table :data="form['fields']" border>
          <el-table-column type="index" label="序号" width="60" />
          <el-table-column prop="name" label="字段名称" />
          <el-table-column prop="fieldType" label="字段类型" show-overflow-tooltip :formatter="row => fieldType[row.fieldType]" />
          <el-table-column prop="value" label="字段值/表达式" show-overflow-tooltip>
            <template #default="scope">
              <template v-if="scope.row.fieldType === 'string'">{{ scope.row.string }}</template>
              <template v-else>{{ scope.row.expression }}</template>
            </template>
          </el-table-column>
          <el-table-column prop="operate" label="操作" width="110" align="center">
            <template #default="scope">
              <el-button type="primary" icon="Edit" circle @click="edit(scope.row, scope.$index)"></el-button>
              <el-button type="danger" icon="Delete" circle @click="deleteRow(scope.$index)"></el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-button class="add" type="primary" icon="Plus" @click="add">添加字段</el-button>
      </div>
      <FieldsAddEdit ref="FieldsAddEditRef" @save="fieldListChange"></FieldsAddEdit>
    </template>
    <template #footer>
      <div class="drawer-footer">
        <el-button @click="cancel">取消</el-button>
        <el-button type="primary" @click="save">保存</el-button>
      </div>
    </template>
  </el-drawer>
</template>
<style scoped lang="scss">
.field-content {
  padding-right: 6px;

  .el-button.add {
    width: 100%;
    margin: 12px 0 0;
  }
}

.divider-panel {
  display: flex;
  align-items: center;

  span {
    margin-left: 6px;
  }
}
</style>
<style lang="scss">
.listener-drawer {

  .el-drawer__header {
    margin: 0;
    padding: 15px var(--el-space);
    border-bottom: 1px solid var(--el-border-color-extra-light);

    h2 {
      font-weight: bold;
      font-size: 14px;
    }
  }

  .el-drawer__body {
    position: relative;
    padding: calc(var(--el-space) - 8px) calc(var(--el-space) - 8px) calc(var(--el-space) - 8px) calc(var(--el-space) - 2px);
  }

  .el-drawer__footer {
    padding: 12px;
    border-top: 1px solid var(--el-border-color-extra-light);

    .drawer-footer {
      display: flex;

      .el-button {
        flex: 1;
        margin: 6px;
      }
    }
  }
}
</style>
